
#include <iostream>
#include <fstream>
#include <vector>

#define TO(x) (const uint8_t*)(x)

double uint_factor[] = {100000000, 10000, 1000, 100, 10, 1, 0.1, 0.01};

std::vector<const uint8_t*> num_list[] = {
    {TO("零"), TO("0"), TO("〇")} ,
    {TO("壹"), TO("1"), TO("一")},
    {TO("贰"), TO("2"), TO("二")},
    {TO("叁"), TO("3"), TO("三")},
    {TO("肆"), TO("4"), TO("四")},
    {TO("伍"), TO("5"), TO("五")},
    {TO("陆"), TO("6"), TO("六")},
    {TO("柒"), TO("7"), TO("七")},
    {TO("捌"), TO("8"), TO("八")},
    {TO("玖"), TO("9"), TO("九")}
};

std::vector<const uint8_t*> unit_list[] = {
    {TO("亿"), TO("乙")},
    {TO("万"), TO("萬")},
    {TO("仟"), TO("千")},
    {TO("佰"), TO("百")},
    {TO("拾"), TO("十")},
    {TO("圆"), TO("元")},
    {TO("角")},
    {TO("分")}
};

std::vector<const uint8_t*> other_list = { TO("整"), TO("正") };

const int UNIT_OFFSET = 1;
const int NUM_OFFSET = 2;

typedef enum {
    CONVERT_TYPE_FEN,
    CONVERT_TYPE_YUAN,
    CONVERT_TYPE_WAN,
    CONVERT_TYPE_YI,
} conv_type_t;

static double to_num(const std::vector<int> &test_list, conv_type_t type)
{
    int index = 0;
    double data = 0, unit = 0;

    switch (type)
    {
    case CONVERT_TYPE_FEN:
        unit = 1.0;
        break;
    case CONVERT_TYPE_YUAN:
        unit = 1.0;
        break;
    case CONVERT_TYPE_WAN:
        unit = 10000.0;
        break;
    case CONVERT_TYPE_YI:
        unit = 100000000.0;
        break;
    default:
        return -1;
    }

    while (index < (int)(test_list.size() - 1))
    {
        if (test_list[index] == (NUM_OFFSET * 100 + 0) &&
            (test_list[index + 1] / 100) == NUM_OFFSET)
        {
            ++ index;
            continue;
        }
        if (test_list[index] == (NUM_OFFSET * 100 + 0) &&
            type == CONVERT_TYPE_FEN && (test_list[index + 1] / 100) == UNIT_OFFSET)
        {
            index += 2;
            continue;
        }
        if ((test_list[index] / 100) == NUM_OFFSET &&
            (test_list[index + 1] / 100) == UNIT_OFFSET)
        {
            if (index == (test_list.size() - 2) && type != CONVERT_TYPE_FEN)
            {
                data = data + (test_list[index] % 100);
            }
            else
            {
                data = data + (test_list[index] % 100) * uint_factor[test_list[index + 1] % 100];
            }
            index = index + 2;
        }
        else
        {
            return -2;
        }
    }
    return data * unit;
}

static bool check_word(const uint8_t* word, int word_len, std::vector<const uint8_t*> &list)
{
    for (int i = 0; i < list.size(); i ++)
    {
        const uint8_t* element = list[i];
        int element_len = 0;
        int result_cnt = 0;
        for (int j = 0; element[j] != 0 && j < word_len; j++)
        {
            element_len++;
            if (element[j] == word[j])
            {
                result_cnt++;
            }
        }
        if (element_len == result_cnt && element_len == word_len)
        {
            return true;
        }
    }
    return false;
}

static int convert_string_to_list(const uint8_t* s, int slen, std::vector<int> &list)
{
    for (size_t i = 0; i < slen;)
    {
        int cplen;

        if ((s[i] & 0xf8) == 0xf0) cplen = 4;
        else if ((s[i] & 0xf0) == 0xe0) cplen = 3;
        else if ((s[i] & 0xe0) == 0xc0) cplen = 2;
        else cplen = 1;
        if ((i + cplen) > slen) cplen = 1;

        const uint8_t* word = s + i;
        int word_len = cplen;

        i += cplen;

        bool find_result = false;

        if (!find_result)
        {
            for (auto j = 0; j < sizeof(unit_list) / sizeof(unit_list[0]); j++)
            {
                if (check_word(word, word_len, unit_list[j]))
                {
                    find_result = true;
                    list.push_back(UNIT_OFFSET * 100 + j);
                    break;
                }
            }
        }
        if (!find_result)
        {
            for (auto j = 0; j < sizeof(num_list) / sizeof(num_list[0]); j++)
            {
                if (check_word(word, word_len, num_list[j]))
                {
                    find_result = true;
                    list.push_back(NUM_OFFSET * 100 + j);
                    break;
                }
            }
        }
        if (!find_result)
        {
            if (check_word(word, word_len, other_list))
            {
                find_result = true;
                break;
            }
        }

        if (!find_result)
        {
            return -3;
        }
    }
    return 0;
}

static int split_list(const std::vector<int>& raw_list, std::vector<int>& yi_list,
    std::vector<int>& wan_list, std::vector<int>& yuan_list, std::vector<int>& fen_list)
{
    int next_find = 0;
    for (int i = next_find; i < raw_list.size(); i++)
    {
        if (raw_list[i] == (UNIT_OFFSET * 100 + 0))
        {
            for (int j = next_find; j < i + 1; j++)
            {
                yi_list.push_back(raw_list[j]);
            }
            next_find = i + 1;
            break;
        }
    }

    for (int i = next_find; i < raw_list.size(); i++)
    {
        if (raw_list[i] == (UNIT_OFFSET * 100 + 1))
        {
            for (int j = next_find; j < i + 1; j++)
            {
                wan_list.push_back(raw_list[j]);
            }
            next_find = i + 1;
            break;
        }
    }

    for (int i = next_find; i < raw_list.size(); i++)
    {
        if (raw_list[i] == (UNIT_OFFSET * 100 + 5))
        {
            for (int j = next_find; j < i + 1; j++)
            {
                yuan_list.push_back(raw_list[j]);
            }
            next_find = i + 1;
            break;
        }
    }

    for (int i = next_find; i < raw_list.size(); i++)
    {
        fen_list.push_back(raw_list[i]);
    }

    return 0;
}

static double list_to_num(const std::vector<int>& yi_list, const std::vector<int>& wan_list,
    const std::vector<int>& yuan_list, const std::vector<int>& fen_list)
{
    if (yi_list.size() == 1 || wan_list.size() == 1 || fen_list.size() == 1 || yuan_list.size() < 1)
    {
        return -4;
    }

    double yi = to_num(yi_list, CONVERT_TYPE_YI);
    if (yi < 0)
    {
        return yi;
    }
    double wan = to_num(wan_list, CONVERT_TYPE_WAN);
    if (wan < 0)
    {
        return wan;
    }
    double yuan = to_num(yuan_list, CONVERT_TYPE_YUAN);
    if (yuan < 0)
    {
        return yuan;
    }
    double fen = to_num(fen_list, CONVERT_TYPE_FEN);
    if (fen < 0)
    {
        return fen;
    }
    return (yi + wan + yuan + fen);
}

static double ch_string_to_num(const uint8_t* s, int slen)
{
    if (slen <= 0)
    {
        return -5;
    }

    std::vector<int> raw_list, yi_list, wan_list, yuan_list, fen_list;
    int ret = convert_string_to_list(s, slen, raw_list);
    if (ret != 0) {
        return ret;
    }
    ret = split_list(raw_list, yi_list, wan_list, yuan_list, fen_list);
    if (ret != 0) {
        return ret;
    }

    return list_to_num(yi_list, wan_list, yuan_list, fen_list);
}

static int remove_space(char *buffer)
{
    int buffer_len = 0;
    for (int i = 0; buffer[i] != 0; i++)
    {
        buffer_len ++;
    }
    for (int i = 0; i < buffer_len;)
    {
        if (buffer[i] == ' ' || buffer[i] == '\t' ||
            buffer[i] == '\r' || buffer[i] == '\n')
        {
            for (int j = i + 1; j < buffer_len; j++)
            {
                buffer[j - 1] = buffer[j];
            }
            buffer_len --;
        }
        else
        {
            i++;
        }
    }
    buffer[buffer_len] = 0;
    return buffer_len;
}

int main(void)
{
    std::ifstream in("1.txt");
    std::ofstream out("1.csv");

    if (!in.is_open())
    {
        return -6;
    }

    while (!in.eof())
    {
        char in_buffer[1024];
        in.getline(in_buffer, sizeof(in_buffer) - 2);
        int in_len = remove_space(in_buffer);
        double result = ch_string_to_num((uint8_t*)in_buffer, in_len);
    
        char out_buffer[1024];
        int out_len = 0;
        if (result == -5.0)
        {
            out_len = snprintf(out_buffer, sizeof(out_buffer) - 2, "%s, ,\n", in_buffer);
        }
        else if (result < 0)
        {
            out_len = snprintf(out_buffer, sizeof(out_buffer) - 2, "%s, 错误%u,\n", in_buffer, uint32_t(-result));
        }
        else
        {
            out_len = snprintf(out_buffer, sizeof(out_buffer) - 2, "%s, %.2f,\n", in_buffer, result);
        }
        out.write(out_buffer, out_len);
    }
	return 0;
}
